use scraper::Selector;
use thiserror::Error;
use async_trait::async_trait;
use common::compose::{CallCore, ContextBox, FError};
use serde::{Deserialize, Serialize};


#[derive(Error, Debug)]
pub enum SpiderError {
    #[error("网络请求错误: {0}")]
    RequestError(#[from] reqwest::Error),

    #[error("HTML解析错误: {0}")]
    ParseError(String),

    #[error("选择器语法错误: {0}")]
    SelectorError(#[from] scraper::error::SelectorErrorKind<'static>),

    #[error("JSON序列化错误: {0}")]
    SerdeError(#[from] serde_json::Error),

    #[error("任务配置错误: {0}")]
    ConfigError(String),

    #[error("IO错误: {0}")]
    IoError(#[from] std::io::Error),

    #[error("数据库错误: {0}")]
    DbError(String),

    #[error("未知错误: {0}")]
    Unknown(#[from] anyhow::Error),
}

impl From<SpiderError> for FError {
    fn from(error: SpiderError) -> Self {
        match error {
            SpiderError::ParseError(e) => FError::ParseError(e),
            SpiderError::ConfigError(e) => FError::ConfigError(e),
            _ => FError::Generic(error.to_string()),
        }
    }
}


#[derive(Clone, Serialize, Deserialize)]
pub struct TaskConfig {
    pub task_id: String,
    pub parallel: usize,
    pub total_page: usize,
    pub url_template: String, // https://example.com/list?page={page}
    pub list_css: String,
    pub content_css: String,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct TaskStatus {
    pub current: usize,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Article {
    pub title: String,
    pub url: Option<String>,
    pub content: Option<String>,
    pub children: Option<Vec<Article>>,
}

pub struct NextPageGenerator {
    save_status: Box<dyn CallCore<(String, String), usize>>,
}
impl NextPageGenerator {
    pub fn new(save_status: Box<dyn CallCore<(String, String), usize>>) -> Self {
        Self {
            save_status
        }
    } 
}

#[async_trait]
impl
    CallCore<
        (TaskConfig,TaskStatus),
        Option<String>,
    > for NextPageGenerator
{
    async fn run(
        &self,
        arg: (TaskConfig, TaskStatus),
        ctx: ContextBox
    ) -> Result<Option<String>, FError> {
        let (config, mut status) = arg;

        // 如果当前页码超过总页数，返回 None 表示任务结束
        if status.current > config.total_page {
            return Ok(None);
        }

        // 使用模板生成下一页的 URL
        let url = config
            .url_template
            .replace("{page}", &(status.current).to_string());
        status.current += 1;

        let json = serde_json::to_string(&status).map_err(|e| FError::Generic(e.to_string()))?;
        self.save_status.run((config.task_id.clone(), json), ctx).await?;

        Ok(Some(url))
    }
}


async fn get_list_node_html((html, css): (String, String)) -> Result<String, FError> {
    // 解析html
    let document = scraper::Html::parse_document(&html);
    // 选择节点
    let selector = Selector::parse(&css)
        .map_err(|e| SpiderError::ParseError(format!("选择器语法错误: {}", e)))?;
    let node = document.select(&selector).next()
        .ok_or_else(|| SpiderError::ParseError("Node not found".to_string()))?;

    // 输出节点的 HTML 内容
    Ok(node.html())
}

async fn clear_attribute(html: String) -> Result<String, FError> {
    use kuchiki::traits::*;
    
    // 使用kuchiki解析HTML
    let document = kuchiki::parse_html().one(html);
    
    // 首先移除所有注释节点
    let mut comments_to_remove = Vec::new();
    for node in document.inclusive_descendants() {
        if node.as_comment().is_some() {
            comments_to_remove.push(node);
        }
    }
    
    // 删除收集到的注释节点
    for comment in comments_to_remove {
        if let Some(parent) = comment.parent() {
            parent.children().filter(|n| *n == comment).for_each(|n| n.detach());
        }
    }
    
    // 选择所有元素，清除属性
    for node in document.inclusive_descendants() {
        if let Some(element) = node.as_element() {
            let mut attributes = element.attributes.borrow_mut();
            
            // 保存href属性值
            let href_value = attributes.get("href").map(|s| s.to_string());
            
            // 清除所有属性
            attributes.map.clear();
            
            // 如果有href属性，则恢复它
            if let Some(href) = href_value {
                attributes.insert("href", href);
            }
        }
    }
    
    // 将修改后的DOM树序列化为HTML字符串
    let mut result = Vec::new();
    
    // 只序列化body内的内容，而不是整个HTML文档
    if let Some(body) = document.select_first("body").ok() {
        // 序列化body的子节点，而不是body本身
        for child in body.as_node().children() {
            child.serialize(&mut result).map_err(|e| SpiderError::ParseError(e.to_string()))?;
        }
    } else {
        // 如果没有body标签（可能是HTML片段），则序列化整个文档
        document.serialize(&mut result).map_err(|e| SpiderError::ParseError(e.to_string()))?;
    }
    
    let cleaned_html = String::from_utf8(result).map_err(|e| SpiderError::ParseError(e.to_string()))?;
    
    // 移除空白行和多余的空格
    let cleaned_html = cleaned_html.lines()
        .map(|line| line.trim())
        .filter(|line| !line.is_empty())
        .collect::<Vec<_>>()
        .join("\n");
    
    Ok(cleaned_html)
}

async fn get_article_content(((config, _), html): ((TaskConfig, TaskStatus), String)) -> Result<String, FError> {
    let content_css = config.content_css;
    let document = scraper::Html::parse_document(&html);
    let selector = Selector::parse(&content_css)
       .map_err(|e| SpiderError::ParseError(format!("选择器语法错误: {}", e)))?;
    let node = document.select(&selector).next()
      .ok_or_else(|| SpiderError::ParseError("Node not found".to_string()))?;

    // 输出节点的 HTML 内容
    Ok(node.html())
}

#[cfg(test)]
mod tests {
    use std::{env, sync::Arc};

    use common::{agent::init_agent, compose::{CallBox, Composer, ListHandler}, tools::make_fetcher};
    use db::{models::{SpiderTask, SpiderTaskStatus}, frunable::{save_task_status, SpiderTaskGetter, SpiderTaskStatusGetter}};
    use dotenvy::dotenv;

    use crate::prompt::list_tree::LIST_TREE;

    use super::*;

    #[tokio::test]
    async fn test_clear_attribute() {
        // 测试用的HTML，包含各种属性
        let html = r#"
        <div class="container" id="main">
            <a href="https://example.com" class="link" target="_blank">Example Link</a>
            <p style="color: red;" data-test="value">Some text</p>
            <img src="image.jpg" alt="Image" width="100" height="100">
        </div>
        "#;

        // 调用clear_attribute函数
        let result = clear_attribute(html.to_string()).await.unwrap();
        println!("{}", result);

        // 验证结果：只保留了href属性
        assert!(result.contains(r#"<a href="https://example.com">"#));
        
        // 验证其他属性被清除
        assert!(!result.contains(r#"class="link""#));
        assert!(!result.contains(r#"target="_blank""#));
        assert!(!result.contains(r#"style="color: red;""#));
        assert!(!result.contains(r#"data-test="value""#));
        assert!(!result.contains(r#"src="image.jpg""#));
        assert!(!result.contains(r#"alt="Image""#));
        assert!(!result.contains(r#"width="100""#));
        assert!(!result.contains(r#"height="100""#));
        
        // 验证HTML结构和文本内容保持不变
        assert!(result.contains("Example Link"));
        assert!(result.contains("Some text"));
        assert!(result.contains("<div>"));
        assert!(result.contains("<p>"));
        assert!(result.contains("<img>"));
    }


    #[tokio::test]
    async fn test() {
        dotenv().ok();

        let runable = Composer::compose(
            Composer::compose_parallel(
                Composer::compose(
                    Arc::new(Box::new(SpiderTaskGetter {})),
                    Composer::from_fn(|entity: SpiderTask| Box::pin(async move {
                        serde_json::from_str::<TaskConfig>(&entity.task_schema)
                            .map_err(|e| FError::ParseError(e.to_string()))
                    }))
                ),
                Composer::compose(
                    Arc::new(Box::new(SpiderTaskStatusGetter {})),
                    Composer::from_fn(|entity: SpiderTaskStatus| Box::pin(async move {
                        serde_json::from_str::<TaskStatus>(&entity.task_data)
                            .map_err(|e| FError::ParseError(e.to_string()))
                    }))
                )
            ),
            Composer::with_context_params(
                "task_info_holder".to_string(),
                Composer::compose_parallel(
                    Composer::compose(
                        Arc::new(Box::new(NextPageGenerator::new(save_task_status()))), 
                        Composer::wrap_option(
                            make_fetcher(), 
                            Composer::from_fn(|_| Box::pin(async move {
                                Err(FError::ParseError("没有下一页了".to_string()))
                            }))
                        )
                    ),
                    Composer::from_fn(|(config, _): (TaskConfig, _)| Box::pin(async move {
                        Ok(config.list_css)
                    }))
                )
            ),
        );

        let key = env::var("DEEPSEEK_API_KEY").unwrap();
        let agent_handler = init_agent(LIST_TREE, &key);

        let page_handler = Composer::compose3(
            Composer::from_fn(get_list_node_html),
            Composer::from_fn(clear_attribute),
            agent_handler
        );

        // 入参是task_id，返回值是Vec<Article>  这里已经获取到文章列表了
        let fetch_list_runner = Composer::compose3(
            runable, 
            page_handler,
            Composer::from_fn(|json: String| Box::pin(async move {Ok(serde_json::from_str::<Vec<Article>>(&json).map_err(|e| FError::ParseError(e.to_string()))?)}))
        );

        let list_handler_rec = Composer::compose(
            Composer::compose_parallel_simple(
                Composer::with_callbox::<(TaskConfig, TaskStatus)>("task_info_holder"), 
                Composer::identity::<((CallBox<Vec<Article>, Vec<Article>>, CallBox<Article, Article>), Vec<Article>)>()), 
            Composer::compose_parallel(
                Composer::from_fn(async|((config, _), ((_, item_handler), _)): ((TaskConfig, _), ((_, CallBox<Article, Article>), _))| {
                    Ok(Box::new(ListHandler::new(config.parallel, item_handler)))
                }), 
                Composer::from_fn(async|(_, (_, article)): (_, (_, Vec<Article>))| {
                    Ok(article)
                })
            )

            // Composer::from_fn2(|(handler, articles): (Box<ListHandler<Article, Article>>, Vec<Article>), ctx: &CallContext| Box::pin(async move {
            //     handler.run(articles, ctx).await
            // }))
        );

        // let item_handler_rec = Composer::compose(
        //     Composer::identity::<((CallBox<Article, Article>, CallBox<Vec<Article>, Vec<Article>>), Article)>(), 
        //     Composer::from_fn(async|((_, _), article)| {
        //         Ok(article.url)
        //     })
        // );



        // let task_id = "1".to_string();
        // let res = fetch_list_runner.run(task_id, &CallContext::new()).await;
        // assert!(res.is_ok());

        // println!("{:?}", res.unwrap());

    }

    #[test]
    fn test_json() {
        let json = r#"
[
    {
        "title": "章节标题",
        "url": "可选链接",
        "children": [
            {
                "title": "子章节标题",
                "url": "可选子链接"
            },
            {
                "title": "子章节标题2"
            },
            {
                "title": "子章节标题2",
                "url": "可选子链接2",
                "children": [
                    {
                        "title": "子章节标题2",
                        "url": "可选子链接2"
                    }
                ]
            }
        ]
    },
    {
        "title": "章节标题2"
    }
]
"#;
        let res: Vec<Article> = serde_json::from_str(json).unwrap();
        println!("{:?}", res);
        assert!(res.len() > 0);
        assert_eq!(res[0].title, "章节标题");
    }
}